// #include <iostream>
#include <thread>
#include <functional>

// using namespace std;

// void Print(size_t n, int &rx)
// {
//     for (size_t i = 0; i < n; i++)
//     {
//         cout << "thread ID : " << this_thread::get_id() << " " << i << endl;
//         rx++;
//     }
// }

// int main()
// {
//     int x = 2;
//     thread t1(Print, 10, ref(x)); // ref -> <functional>

//     t1.join();

//     cout << x << endl;
//     return 0;
//}

// int main()
// {
//     //使用lambda
//     //创建两个线程，执行++x n次（n1，n2）。输出x结果
//     int n1,n2;
//     cin >> n1 >> n2;

//     int x = 0;

//     thread t1([n1, &x](){
//             for(int i = 0; i< n1;i++)
//                 ++x;
//             });
//     thread t2([n2, &x](){
//             for(int i = 0; i< n2;i++)
//                 ++x;
//             });

//     t1.join();
//     t2.join();

//     cout << x << endl;
//     return 0;
// }

// void Print(size_t n)
// {
//     for (size_t i = 0; i < n; i++)
//     {
//         cout << "thread ID : "<< this_thread::get_id() << " " << i << endl;
//     }

// }

// int main()
// {
//     thread t1(Print,6);
//     //移动构造
//     thread t2(move(t1));

//     t2.join();
//     return 0;
// }

// int main()
// {
//     //假设创建n个线程去执行Print方法
//     int n = 0;
//     cin >> n;
//     vector<thread> vthd(n);

//     for(auto& t : vthd)
//     {
//         //移动赋值
//         t = thread(Print, 4);
//     }

//     for(auto& t : vthd)
//         t.join();

//     return 0;
// }

// #include <iostream>
// #include <pthread.h>

// using namespace std;

// void* Print(void* args)
// {
//     size_t n = *((size_t*)args);
//     for (size_t i = 0; i < n; i++)
//     {
//         cout << "thread ID :" << pthread_self()  << " " << i << endl;
//     }

// }

// int main()
// {
//     pthread_t t1,t2;
//     size_t n = 6;
//     pthread_create(&t1, nullptr, Print, &n);
//     pthread_create(&t2, nullptr, Print, &n);

//     //让主线程等待
//     pthread_join(t1,nullptr);
//     pthread_join(t2,nullptr);

//     return 0;
// }

// #include <iostream>
// #include <pthread.h>
// #include <mutex>
// #include <thread>
// #include <stdlib.h>
// #include <stdexcept> 

// #include <chrono>
// using namespace std;
// void func()
// {
//     srand(time(0));
//     if (rand() % 3 == 0)
//     {
//         throw runtime_error("异常");
//     }
//     else
//     {
//         cout << "func()" << endl;
//     }
// }

// // RAII
// template <class Lock>
// class LockGuard
// {
// public:
//     LockGuard(Lock &lk)
//         : _lk(lk)
//     {
//         _lk.lock();
//     }

//     ~LockGuard()
//     {
//         _lk.unlock();
//     }

// private:
//     Lock &_lk;
// };

// int main()
// {
// 	mutex mtx;
// 	size_t n1 = 10000;
// 	size_t n2 = 10000;
	
// 	size_t x = 0;

// 	thread t1([n1, &x, &mtx]() {
// 		try {
// 			for (size_t i = 0; i < n1; i++)
// 			{
// 				//mtx.lock();
//                 LockGuard<mutex> lg(mtx);
// 				++x;
// 				func();

// 				//mtx.unlock();
// 			}
// 		}
// 		catch (const exception& e)
// 		{
// 			cout << e.what() << endl;
// 		}
// 	});
	
// 	thread t2([n2, &x, &mtx]() {
// 		for (size_t i = 0; i < n2; i++)
// 		{
// 			mtx.lock();
// 			++x;
// 			mtx.unlock();
// 		}
// 	});

// 	t1.join();
// 	t2.join();

// 	cout << x << endl;

// 	return 0;
// }


#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

using namespace std;

int main()
{
    mutex mtx;
    condition_variable cv;
    int x = 1;
    bool flag = false; //控制打印顺序

    thread t1([&](){
        for(size_t i = 0; i < 10; i++)
        {
            unique_lock<mutex> lock(mtx); //获取锁。如果t2先获取到，就阻塞在这里等待锁资源被释放
            while(flag) //while保证安全性，避免极端场景下wait失败
                cv.wait(lock); //wait()的瞬间会释放锁
            cout << this_thread::get_id() << ":" << x << endl;
            ++x;
            flag = true; //保证只打印一次
            cv.notify_one(); //若t2在wait，就唤醒，否则什么都不做
        }
    });

    thread t2([&](){
        for(size_t i = 0; i < 10; i++)
        {
            unique_lock<mutex> lock(mtx);//获取锁。如果t1先获取到，就阻塞在这里等待锁资源被释放
            while(!flag)
                cv.wait(lock); //wait()的瞬间会释放锁
            cout << this_thread::get_id() << ":" << x << endl;
            ++x;
            flag = false;//保证只打印一次
            cv.notify_one();//若t1在wait，就唤醒，否则什么都不做
        }
    });

    //主线程等待子线程
    t1.join();
	t2.join();

    return 0;
}
